﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

using SPaDevToolkit.Diagnostics;
using Northwind.Common.Diagnostics;

namespace Northwind.ServiceObjects
{
    [Guid("5A9097B1-137F-480B-B3E0-4A517CAE0FC7")]
    public sealed class NorthwindService : SPIisWebService, IServiceAdministration
    {
        #region Fields
        public static string CreateServiceApplicationLink = "/_admin/Northwind/CreateNorthwindApplication.aspx";
        //REFACTOR: read from resource or config?
        public static string ServiceDefaultTypeName = "Northwind Service";
        public static string ServiceDefaulttDisplayName = "Northwind Service";


        #endregion

        #region Constructors
        public NorthwindService() { }
        public NorthwindService(SPFarm farm): base(farm) { }
        public NorthwindService(string name, SPFarm farm)
			: base(farm)
		{
			// NOTE: This constructor is required if this service is installed by the command
			// psconfig -cmd services -install.

			Name = name;
		}
        #endregion

        #region SPIisWebService Overrides
        public override SPAdministrationLink GetCreateApplicationLink(Type serviceApplicationType)
        {
            return new SPAdministrationLink(string.Format("{0}?Mode=Create", NorthwindService.CreateServiceApplicationLink));
        }

        public override string DisplayName
        {
            get
            {
                return ServiceDefaulttDisplayName;
            }
        }

        public override string TypeName
        {
            get
            {
                return ServiceDefaultTypeName;
            }
        }
        #endregion

        #region IServiceAdministration Members
        public SPServiceApplication CreateApplication(string name, Type serviceApplicationType, SPServiceProvisioningContext provisioningContext)
        {
            Logger.WriteTrace(string.Format("Creating service application '{0}' through service '{1}'", name, Name), 0, TraceSeverity.High, AreaNames.Northwind, CategoryNames.Service);
            try
            {
                if (serviceApplicationType != typeof(NorthwindApplication))
                {
                    throw new NotSupportedException("Incorrect service application type specified: " + serviceApplicationType.FullName);
                }
                NorthwindApplication application = this.Applications.GetValue<NorthwindApplication>(name);
                if (application != null)
                {
                    return application;
                }

                //REFACTOR: Application database creation
                SPDatabaseParameters northwindDatabaseParameters = SPDatabaseParameters.CreateParameters(name + "_Northwind", SPDatabaseParameterOptions.GenerateUniqueName);

                northwindDatabaseParameters.Validate(SPDatabaseValidation.CreateNew);
                application = NorthwindApplication.Create(name, this, (provisioningContext != null) ? provisioningContext.IisWebServiceApplicationPool : null, northwindDatabaseParameters);
                
                Logger.WriteTrace(string.Format("Finsinhed Creating service application '{0}' through service '{1}'", name, Name), 0, TraceSeverity.High, AreaNames.Northwind, CategoryNames.Service);

                return application;
            }
            catch (Exception ex)
            {
                Logger.WriteException(ex, string.Format("Error creating service application '{0}' through service '{1}'", name, Name), 0, EventSeverity.Error, AreaNames.Northwind, CategoryNames.Service);
                throw;
            }

        }

        public SPServiceApplicationProxy CreateProxy(string name, SPServiceApplication serviceApplication, SPServiceProvisioningContext provisioningContext)
        {
            Logger.WriteTrace(string.Format("Creating service application proxy '{0}' through service '{1}'", name, Name), 0, TraceSeverity.High, AreaNames.Northwind, CategoryNames.Service);
            try
            {
                if (null == serviceApplication)
                {
                    throw new ArgumentNullException("serviceApplication");
                }
                if (serviceApplication.GetType() != typeof(NorthwindApplication))
                {
                    throw new NotSupportedException();
                }
                NorthwindServiceProxy serviceProxy = (NorthwindServiceProxy)base.Farm.GetObject(NorthwindServiceProxy.DefaultName, base.Farm.Id, typeof(NorthwindServiceProxy));
                if (null == serviceProxy)
                {
                    throw new InvalidOperationException();
                }
                NorthwindApplicationProxy serviceApplicationProxy = serviceProxy.ApplicationProxies.GetValue<NorthwindApplicationProxy>(name);
                if (serviceApplicationProxy != null)
                {
                    return serviceApplicationProxy;
                }
                NorthwindApplication application = serviceApplication as NorthwindApplication;

                Logger.WriteTrace(string.Format("Finished Creating service application proxy '{0}' through service '{1}'", name, Name), 0, TraceSeverity.High, AreaNames.Northwind, CategoryNames.Service);
                
                return new NorthwindApplicationProxy(name, serviceProxy, application.Uri);
            }
            catch (Exception ex)
            {
                Logger.WriteException(ex, string.Format("Error creating service application proxy '{0}' through service '{1}'", name, Name), 0, EventSeverity.Error, AreaNames.Northwind, CategoryNames.Service);
                throw;
            }

        }

        public SPPersistedTypeDescription GetApplicationTypeDescription(Type serviceApplicationType)
        {
            if (serviceApplicationType != typeof(NorthwindApplication))
            {
                throw new NotSupportedException();
            }
            return new SPPersistedTypeDescription(NorthwindApplication.ServiceApplicationDefaultTypeName, NorthwindApplication.ServiceApplicationDefaultTypeDescription);
        }

        public Type[] GetApplicationTypes()
        {
            return new Type[] { typeof(NorthwindApplication) };

        }
        #endregion

        #region Other
        public static NorthwindService Local
        {
            get { return SPFarm.Local.Services.GetValue<NorthwindService>(); }
        }

        #endregion
    }
}
